#ifndef xpack_graphic_draw_line
#define xpack_graphic_draw_line
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::graphic_draw_line::inc
#include"define/base_type.hpp"
#include"graphic/draw/lineh.hpp"
#include"graphic/draw/linev.hpp"
#include"graphic/private/rander_helper.hpp"
#include"macro/xexport.hpp"
#include"math/abs.hpp"
#include"math/point.hpp"
#pragma pop_macro("xuser")

namespace mixc::graphic_draw_line::inc{
    template<class rander_t>
    inline void line_core(inc::pt2wx p0, inc::pt2wx p1, rander_t const & rander){
        auto dis        = p1 - p0;

        enum{ half = xbitsof(uxx) / 2 };
        ixx x           = p0->x;
        ixx y           = p0->y;
        ixx absx        = inc::abs(dis->x());
        ixx absy        = inc::abs(dis->y());
        ixx temp        = 0;

        // 如果用到了新的 rander_helper::set_xxx() 接口，需要补充上下文
        auto old_mode   = rander_helper::get_thickness_mode(rander);

        // 斜率大于 45 度，小于 90 度
        if (absx < absy){
            inc::rander_helper::set_thickness_mode(rander, inc::thickness_mode_t::become_wider);
            ixx k       = (ixx(dis->x) << half) / absy;
            ixx sk      = (ixx(p0->x) << half);
            ixx step_y  = (dis->y > 0 ? 1 : -1);

            do{
                rander(uxx(x), uxx(y));
                sk     += k;
                x       = sk >> half;
                temp    = y;
                y      += step_y;
            }while(temp != p1->y);
        }
        // 斜率小于 45 度
        else{
            inc::rander_helper::set_thickness_mode(rander, inc::thickness_mode_t::become_thick);
            ixx k       = (ixx(dis->y) << half) / absx;
            ixx sk      = (ixx(p0->y) << half);
            ixx step_x  = (dis->x > 0 ? 1 : -1);

            do{
                rander(uxx(x), uxx(y));
                sk     += k;
                y       = sk >> half;
                temp    = x;
                x      += step_x;
            }while(temp != p1->x);
        }
        rander_helper::set_thickness_mode(rander, old_mode);
    }
}

namespace mixc::graphic_draw_line::origin{
    template<class rander_t>
    inline void line(inc::pt2wx p0, inc::pt2wx p1, rander_t const & rander){
        auto dis = p1 - p0;

        if (dis->x == 0){
            if (dis->y > 0){
                return inc::draw::linev(p0,  dis->y + 1, rander);
            }
            else{
                return inc::draw::linev(p1, -dis->y + 1, rander);
            }
        }

        if (dis->y == 0){
            if (dis->x > 0){
                return inc::draw::lineh(p0,  dis->x + 1, rander);
            }
            else{
                return inc::draw::lineh(p1, -dis->x + 1, rander);
            }
        }

        inc::line_core(p0, p1, rander);
    }
}
#endif

xexport_spacex(draw, mixc::graphic_draw_line::origin)
